import { _decorator, Component, RigidBody, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
import { Game } from './core/Game';
import { Databus } from './core/Databus';
import { BilliardGame } from './game/BilliardGame';
import { EventManager } from './core/EventManager';
import { GameDataAdaptor } from './game/GameDataAdaptor';
import { SendWebSocket } from './websocket/SendWebSocket';
import { GameUserInstance } from './user/GameUserInstance';
import { SoundManager } from './framework/SoundManager';
import DataEventReport from './platform/DataEventReport';
import { uniConfig } from './config/UniConfig';

const databus = Databus.Instance();

@ccclass('GameController')
export class GameController extends Component {
  private timestamp = 0;
  onLoad() {
    EventManager.Instance().AddEventListener('EndGame', this, this.endGame);
    EventManager.Instance().AddEventListener('RestartGame', this, this.restartGame);
    EventManager.Instance().AddEventListener('WebEndGame', this, this.webEndGame);
  }
  start() {
    this.startGame();
    EventManager.Instance().Emit('CameraRestartGame', {});
  }
  restartGame() {
    DataEventReport.Instance().reportCoreProcess(
      databus.sceneStack.currentPageName(), 'RestartGame',
      Game.Instance().battleCate.valueBattle(),
      Game.Instance().gameType.valueType(),
    );
    this.startGame();
    EventManager.Instance().Emit('CameraRestartGame', {});
    
  }
  update(deltaTime: number) {
    this.timestamp += 1;
    BilliardGame.Instance().currentFrameSeq += 1;
    GameUserInstance.Instance().updateFrame(deltaTime);
    if (this.timestamp % 3 !== 0) return;
    // 1. 游戏结束判断
    if (Game.Instance().status.isEnded()) {
      return;
    }

    // 2. 还未用力击球，不用关注
    if (BilliardGame.Instance().actionStage.isForceFinished()) {
      // 速度比较小则直接静止
      if (this.isAllBallsStopped()) {
        BilliardGame.Instance().actionStage.coolingPeriod();
      }
      return;
    }
    // 3. 冷静期，直接返回
    if (BilliardGame.Instance().actionStage.isCoolingPeriod()) {
      if (BilliardGame.Instance().actionStage.coolingFinished(this.isAllBallsCompleteStopped())) {
        BilliardGame.Instance().sleepAllBalls();
        BilliardGame.Instance().actionStage.waitConfirm();
      }
      return;
    }
    // 4. 等待对手确认
    if (BilliardGame.Instance().actionStage.isWaitConfrim()) {
      if (GameUserInstance.Instance().syncEndStep()) {
        GameUserInstance.Instance().endStep();
        // 变更下一步击球
        this.changeNextStep();
      }
    }
  }
  // 控制变更下一步击球
  public changeNextStep() {
    // 检查是否存在犯规击球
    BilliardGame.Instance().checkIllegalHitBall();
    // 是否不用考虑球的花色
    const isIgnoreColorStage = Game.Instance().isIgnoreColorStage();
    if (BilliardGame.Instance().isIllegalHitBall) { // 违规击球：罚分，交换击球，自由球
      BilliardGame.Instance().penalyUserScore();
      BilliardGame.Instance().swapCurrentUserColor(true);
      BilliardGame.Instance().exchangeUser();
      BilliardGame.Instance().freeKickBall();
      EventManager.Instance().Emit('ChangeUserHitBall', {});
    } else if (!BilliardGame.Instance().hasHoledScore()) { // 未进球得分：交换交换
      BilliardGame.Instance().swapCurrentUserColor(true);
      BilliardGame.Instance().exchangeUser();
      EventManager.Instance().Emit('ChangeUserHitBall', {});
    } else { // 进球得分：更新分数继续击球
      BilliardGame.Instance().updateUserScore();
      BilliardGame.Instance().swapCurrentUserColor(false);
    }
    // 检查游戏是否结束，如果游戏已经结束，没有必要下一步了
    BilliardGame.Instance().checkGameEnd();
    // 游戏结束判断
    if (Game.Instance().status.isEnded()) {
      console.log('current game is end ', Game.Instance().playUsers);
      return;
    }
    // 检查是否需要将进洞的球拿出来重置
    BilliardGame.Instance().checkOutHoleBalls(isIgnoreColorStage);
    if (Game.Instance().isSelftHitBall()) {
      BilliardGame.Instance().showAllOperation();
    }
    this.startStep();
  }
  // 开始新的step击球
  public startStep() {
    BilliardGame.Instance().actionStage.initStage();
    // 下一步击球
    Game.Instance().startStep();
    BilliardGame.Instance().startStep();
    GameUserInstance.Instance().startStep();
    EventManager.Instance().Emit('StartStep', {});

    if (Game.Instance().hitBallList.length === 7) {
      DataEventReport.Instance().reportCoreProcess(
        databus.sceneStack.currentPageName(), 'MiddleGameStatus',
        Game.Instance().battleCate.valueBattle(),
        Game.Instance().gameType.valueType(),
      );
    }
  }
  // 结束当前step击球
  public endStep() {
    GameUserInstance.Instance().endStep();
  }
  // 开始游戏
  public startGame() {
    this.node.getParent().getChildByName('EndGameCanvas').active = false;
    Game.Instance().startGame();
    BilliardGame.Instance().startGame();
    EventManager.Instance().Emit('StartGame', {});
    GameUserInstance.Instance().startGame();

    DataEventReport.Instance().reportCoreProcess(
      databus.sceneStack.currentPageName(), 'StartGame',
      Game.Instance().battleCate.valueBattle(),
      Game.Instance().gameType.valueType(),
    );
  }

  // 游戏结束
  public endGame() {
    new SendWebSocket().sendEndGame(Game.Instance().endReason);
    this.processEndGame();
    GameUserInstance.Instance().endGame();
  }

  public webEndGame() {
    this.processEndGame();
  }
  private processEndGame() {
    console.log('controller game end');
    BilliardGame.Instance().endGame();
    
    this.updateGameEndData();
    if (Game.Instance().battleCate.isEndlessBattle()) {
      databus.sceneStack.backHomePage();
      return;
    }
    if (Game.Instance().battleCate.isFancyBattle()) {
      databus.sceneStack.backHomePage();
      return;
    }
    EventManager.Instance().Emit('EndGameEvent', {});
    if (Game.Instance().isSelfWin()) {
      SoundManager.Instance().playGameWin();
    } else {
      SoundManager.Instance().playGameLose();
    }
  }
  private isAllBallsStopped() {
    var isAllStopped = true;
    const v: Vec3 = new Vec3();
    const mainBall = BilliardGame.Instance().getMainWhiteBall();
    const mainBody = mainBall.getComponent(RigidBody);
    mainBody.getLinearVelocity(v);
    if (this.isBallStopped(v, mainBall.worldPosition)) {
      v.x = 0; v.z = 0;
      mainBody.setLinearVelocity(v);
    } else {
      isAllStopped = false;
    }
    const balls = BilliardGame.Instance().getActiveBalls();
    for (const ball of balls) {
      const body = ball.getComponent(RigidBody);
      body.getLinearVelocity(v);
      if (this.isBallStopped(v, ball.worldPosition)) {
        v.x = 0; v.z = 0;
        body.setLinearVelocity(v);
      } else {
        isAllStopped = false;
      }
    }

    return isAllStopped;
  }

  private isBallStopped(v: Vec3, pos: Vec3) {
    const thresv = 0.5;
    const vat = v.x * v.x + v.z * v.z;
    if (vat > thresv) {
      return false;
    }
    if (vat < 0.1) {
      return true;
    }
    const holes = BilliardGame.Instance().getDeskBallHolePosition();
    for (const hole of holes) {
      const dist = (hole.x - pos.x) * (hole.x - pos.x) + (hole.z - pos.z) * (hole.z - pos.z);
      if (dist < 0.0625) { // 0.25的平方
        return false;
      }
    }
    return true;
  }

  private isAllBallsCompleteStopped() {
    const thres = 0.1;
    const v: Vec3 = new Vec3();
    const mainBall = BilliardGame.Instance().getMainWhiteBall();
    const mainBody = mainBall.getComponent(RigidBody);
    if (mainBall.active) {
      mainBody.getLinearVelocity(v);
      const vat = v.x * v.x + v.z * v.z + v.y * v.y;
      if (vat > thres) {
        return false;
      }
    }
    
    const balls = BilliardGame.Instance().getActiveBalls();
    for (const ball of balls) {
      const body = ball.getComponent(RigidBody);
      body.getLinearVelocity(v);
      const vel = v.x * v.x + v.z * v.z + v.y * v.y;
      if (vel > thres) {
        return false;
      }
    }

    return true;
  }

  private updateGameEndData() {
    if (Game.Instance().battleCate.isEndlessBattle()) {
      // TODO: 做历史记录排行榜
      return;
    }
    if (Game.Instance().battleCate.isFancyBattle()) {
      // TODO: 上报历史记录
      return;
    }
    if (Game.Instance().isSelfWin()) {
      GameDataAdaptor.Instance().updateUserGameNum(1);
      GameDataAdaptor.Instance().updateUserPlayLevel(2);
      GameDataAdaptor.Instance().updateUserGoldCoin(uniConfig.WinCoinValue);
      databus.changeAiLevel(1);
      DataEventReport.Instance().reportCoreMetric(
        'win', Game.Instance().battleCate.valueBattle(),
        Game.Instance().gameType.valueType(),
      );
    } else {
      GameDataAdaptor.Instance().updateUserGameNum(-1);
      GameDataAdaptor.Instance().updateUserPlayLevel(-2);
      GameDataAdaptor.Instance().updateUserGoldCoin(-uniConfig.WinCoinValue);
      databus.changeAiLevel(-1);
      DataEventReport.Instance().reportCoreMetric(
        'lose', Game.Instance().battleCate.valueBattle(),
        Game.Instance().gameType.valueType(),
      );
    }
  }
}

